package com.hiss.basic.system.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.hiss.basic.client.system.ISysDeptService;
import com.hiss.basic.model.system.domain.SysDeptDomain;
import com.hiss.basic.model.system.domain.SysUserDomain;
import com.hiss.basic.model.system.request.SysDeptCreateRequest;
import com.hiss.basic.model.system.request.SysDeptQueryRequest;
import com.hiss.basic.model.system.request.SysDeptUpdateRequest;
import com.hiss.basic.model.system.response.SysDeptQueryResponse;
import com.hiss.basic.model.system.response.SysDeptQueryTreeResponse;
import com.hiss.basic.starter.core.constant.SystemConstant;
import com.hiss.basic.starter.core.exception.BusinessException;
import com.hiss.basic.starter.core.helper.MapstructHelper;
import com.hiss.basic.starter.core.helper.ValidationHelper;
import com.hiss.basic.starter.core.utils.tree.TreeBuilder;
import com.hiss.basic.starter.core.utils.tree.TreeNode;
import com.hiss.basic.system.mapper.SysDeptMapper;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Stack;

/**
 * 系统部门 service impl
 */
@Service
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDeptDomain> implements ISysDeptService {

    @Override
    public List<SysDeptQueryResponse> findList(SysDeptQueryRequest request) {
        QueryWrapper wrapper = new QueryWrapper();
        if (ObjectUtil.isNotNull(request)) {
            wrapper.like(SysDeptDomain::getName, request.getName(), StrUtil.isNotBlank(request.getName()));
            wrapper.eq(SysDeptDomain::getEnableStatus, request.getEnableStatus(), ObjectUtil.isNotNull(request.getEnableStatus()));
        }
        wrapper.orderBy(SysDeptDomain::getCreateTime, false);
        return listAs(wrapper, SysDeptQueryResponse.class);
    }

    @Override
    public List<TreeNode<Long, Integer>> findTreeList(SysDeptQueryRequest request) {
        QueryWrapper wrapper = new QueryWrapper();
        if (ObjectUtil.isNotNull(request)) {
            wrapper.like(SysDeptDomain::getName, request.getName(), StrUtil.isNotBlank(request.getName()));
            wrapper.eq(SysDeptDomain::getEnableStatus, request.getEnableStatus(), ObjectUtil.isNotNull(request.getEnableStatus()));
        }

        List<SysDeptQueryTreeResponse> deptList = listAs(wrapper, SysDeptQueryTreeResponse.class);

        List<TreeNode<Long, Integer>> domainList = ListUtil.toList();
        domainList.addAll(deptList);

        return TreeBuilder.build(domainList, parentId -> ObjectUtil.equal(SystemConstant.ROOT_PARENT_ID, parentId),
                Comparator.comparingInt(TreeNode::getWeight));
    }

    @Override
    public List<SysDeptQueryResponse> findChildrenList(Collection<Long> deptIdList) {
        List<SysDeptQueryResponse> deptList = ListUtil.toList();
        Stack<Long> stack = new Stack<>();
        stack.addAll(deptIdList);

        while (!stack.isEmpty()) {
            Long parentId = stack.pop();
            List<SysDeptQueryResponse> childrenList = QueryChain.of(SysDeptDomain.class)
                    .eq(SysDeptDomain::getParentId, parentId)
                    .listAs(SysDeptQueryResponse.class);
            deptList.addAll(childrenList);

            for (SysDeptQueryResponse item : childrenList) {
                stack.push(item.getId());
            }
        }
        return deptList;
    }

    @Override
    public void create(SysDeptCreateRequest request) {
        ValidationHelper.validate(request);
        SysDeptDomain domain = MapstructHelper.convert(request, SysDeptDomain.class);
        if (ObjectUtil.isNull(domain.getParentId())) {
            domain.setParentId(SystemConstant.ROOT_PARENT_ID);
        }
        save(domain);
    }

    @Override
    public void update(SysDeptUpdateRequest request) {
        ValidationHelper.validate(request);
        if (ObjectUtil.equal(request.getId(), request.getParentId())) {
            throw new BusinessException("上级部门不能为自身");
        }
        SysDeptDomain domain = MapstructHelper.convert(request, SysDeptDomain.class);
        if (ObjectUtil.isNull(domain.getParentId())) {
            domain.setParentId(SystemConstant.ROOT_PARENT_ID);
        }
        updateById(domain);
    }

    @Override
    public void remove(Long id) {
        long count = QueryChain.of(SysDeptDomain.class).eq(SysDeptDomain::getParentId, id).count();
        if (count > 0) {
            throw new BusinessException("存在子级部门，无法删除");
        }
        count = QueryChain.of(SysUserDomain.class).eq(SysUserDomain::getDeptId, id).count();
        if (count > 0) {
            throw new BusinessException("部门存在用户，无法删除");
        }
        removeById(id);
    }
}
